extern crate log;

use std::{
    collections::hash_map::RandomState, collections::HashMap, sync::Arc, sync::Mutex,
    time::Duration,
};

use log::info;
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};

use crate::{NACOS_SERVER, PROVIDER_HOST, PROVIDER_NAME, PROVIDER_PORT};

use async_std::task;

use self::nacos_query::Host;

const FRAGMENT: &AsciiSet = &CONTROLS
    .add(b' ')
    .add(b'"')
    .add(b'{')
    .add(b'}')
    .add(b':')
    .add(b',');

///
/// https://nacos.io/
/// http://120.24.162.22:8848/nacos/v1/ns/instance?serviceName=rust-microservice&ip=127.0.0.1&port=8080
///

pub fn register_service() {
    info!("register service: {:?}", NACOS_SERVER);
    task::spawn(async {
        let client = reqwest::blocking::Client::new();
        let body = client
            .post(
                format!(
                    "{}/v1/ns/instance?serviceName={}&ip={}&port={}",
                    NACOS_SERVER, PROVIDER_NAME, PROVIDER_HOST, PROVIDER_PORT
                )
                .as_str(),
            )
            .send()
            .unwrap()
            .text();
        info!("register server response boyd is:{:?}", body);
    });
}

fn ping() {
    let beat = format!(
        "{{\"serviceName\":\"{}\",\"ip\":\"{}\",\"port\":\"{}\",\"weight\":1,\"metadata\":{{}}}}",
        PROVIDER_NAME, PROVIDER_HOST, PROVIDER_PORT
    );
    let encode = utf8_percent_encode(&beat, FRAGMENT).to_string();
    task::spawn(async move {
        let beat_content = format!(
            "{}/v1/ns/instance/beat?serviceName={}&beat={}",
            NACOS_SERVER, PROVIDER_NAME, encode
        );
        let client = reqwest::blocking::Client::new();
        let _body = client.put(beat_content.as_str()).send().unwrap().text();
        // info!("ping result:{:?}", _body);
    });
}

pub fn ping_schedule() {
    info!("ping schedule");
    task::spawn(async {
        loop {
            ping();
            std::thread::sleep(Duration::from_secs(10));
        }
    });
}

pub mod nacos_query {

    use crate::DP_SERVICES;
    use async_std::task;
    use log::info;
    use serde::{Deserialize, Serialize};
    use std::collections::HashMap;
    use std::{collections::hash_map::RandomState, error::Error, sync::Arc, sync::Mutex};
    extern crate serde;
    extern crate serde_json;
    #[derive(Serialize, Deserialize, Debug, Clone)]
    pub struct Host {
        ip: String,
        port: u32,
    }

    #[derive(Serialize, Deserialize, Debug)]
    struct InstanceResponse {
        hosts: Vec<Host>,
    }
    /**
     *拉取服务信息列表.
     */
    pub async fn query_instance_list(service_name: &'static str) {
        task::spawn(async move {
            let client = reqwest::blocking::Client::new();
            let query_param = format!("?serviceName={}", service_name);
            let mut nacos_url = "http://120.24.162.22:8848/nacos/v1/ns/instance/list".to_string();
            nacos_url.push_str(&query_param);
            let instance_list = client.get(&nacos_url).send().unwrap().text().unwrap();
            let instance_response: InstanceResponse = serde_json::from_str(&instance_list).unwrap();

            info!("INSTANCE_LIST_QUERY_URL is :{}", &nacos_url);
            DP_SERVICES
                .lock()
                .unwrap()
                .insert(service_name, instance_response.hosts[0].clone());
            info!("instanceList1 is:{:?}", DP_SERVICES.lock().unwrap());
        });
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use async_std::task;

    #[test]
    fn test_query_instance_list() {
        let result = task::spawn(async {
            let host = crate::nacos::nacos_query::query_instance_list("market-pusher");
            println!("host is :{:?}", host.await);
        });
        std::thread::sleep(Duration::from_secs(2));
        result.task().id();
    }
}
